package net.seabook.games.tetris.model;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

import net.seabook.games.tetris.model.SettingSystem.Score;
import net.seabook.games.tetris.model.Tile.TileColor;

public class TetrisBoard {
	public static final int BOARD_WIDTH = 200;
	public static final int BOARD_HEIGHT = 400;

	public static final int BOARD_GRID_WIDTH = BOARD_WIDTH / Tile.WIDTH;
	public static final int BOARD_GRID_HEIGHT = BOARD_HEIGHT / Tile.HEIGHT;

	private boolean[][] board;

	private List<Integer> fullLineNo = new ArrayList<Integer>(4);

	private Color gridLineColor = Color.LIGHT_GRAY;
	private Color filledTileColor = TileColor.getRandomTileColor();

	private SettingSystem settingSystem;

	public TetrisBoard() {
		board = new boolean[BOARD_GRID_WIDTH][BOARD_GRID_HEIGHT];
		clearBoard();
	}

	public void clearBoard() {
		for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
			for (int j = 0; j < BOARD_GRID_HEIGHT; j++) {
				board[i][j] = false;
			}
		}
	}

	public void drawBoard(Graphics g) {
		// Draw assistant grid lines.
		if (settingSystem.isDrawGrid()) {
			g.setColor(gridLineColor);
			// Horizontal Line
			int y = 0;
			for (int i = 0; i < BOARD_GRID_HEIGHT; i++) {
				g.drawLine(0, y, BOARD_WIDTH, y);
				y += Tile.WIDTH;
			}

			// Vertical Line
			int x = 0;
			for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
				g.drawLine(x, 0, x, BOARD_HEIGHT);
				x += Tile.WIDTH;
			}
		}

		// Draw filled blocks
		for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
			for (int j = 0; j < BOARD_GRID_HEIGHT; j++) {
				if (board[i][j]) {
					g.setColor(Color.GRAY);
					g.fillRect(i * Tile.WIDTH, j * Tile.HEIGHT, Tile.WIDTH,
							Tile.HEIGHT);
				}
			}
		}

	}

	public boolean isGameOver() {
		for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
			if (board[i][0] == true) {
				return true;
			}
		}
		return false;
	}

	public void resetBoard() {

		if (fullLineNo.size() <= 0) {
			return;
		}

		int shiftRowNumber = TetrisBoard.BOARD_GRID_HEIGHT - 1;
		int shiftCount = 0;
		while (true) {
			if (shiftCount >= fullLineNo.size()) {
				break;
			}
			if (isTheLineFull(shiftRowNumber)) {
				dismissTheLine(shiftRowNumber);
				shiftOneRow(shiftRowNumber);
				TetrisHelper.printBoardStatus(this);
				shiftCount++;
			} else
				shiftRowNumber -- ;
		}

		settingSystem.setLines(settingSystem.getLines() + fullLineNo.size());
		settingSystem.setLevel(settingSystem.getLevel());
		settingSystem.setTotalScore(settingSystem.getTotalScore()
				+ calcScore(fullLineNo.size()));

		fullLineNo.clear();

		System.out.println("Level: " + settingSystem.getLevel());
		System.out.println("Lines: " + settingSystem.getLines());
		System.out.println("TotalScore: " + settingSystem.getTotalScore());
	}

	private void shiftOneRow(int row) {
		for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
			for (int j = row; j > 0; j--) {
				board[i][j] = board[i][j - 1];
			}
		}

	}

	private int calcScore(int count) {
		switch (count) {
		case 1:
			return Score.A.getScore();
		case 2:
			return Score.B.getScore();
		case 3:
			return Score.C.getScore();
		case 4:
			return Score.D.getScore();
		}
		return 0;
	}

	public boolean isTheLineFull(int j) {
		for (int i = 0; i < TetrisBoard.BOARD_GRID_WIDTH; i++) {
			if (!board[i][j]) {
				return false;
			}
		}

		return true;
	}

	public void dismissTheLine(int x) {
		for (int i = 0; i < BOARD_GRID_WIDTH; i++) {
			board[i][x] = false;
		}
	}

	public boolean[][] getBoard() {
		return board;
	}

	public void setBoard(boolean[][] board) {
		this.board = board;
	}

	public Color getGridLineColor() {
		return gridLineColor;
	}

	public void setGridLineColor(Color gridLineColor) {
		this.gridLineColor = gridLineColor;
	}

	public Color getFilledTileColor() {
		return filledTileColor;
	}

	public void setFilledTileColor(Color filledTileColor) {
		this.filledTileColor = filledTileColor;
	}

	public SettingSystem getSettingSystem() {
		return settingSystem;
	}

	public void setSettingSystem(SettingSystem scoreSystem) {
		this.settingSystem = scoreSystem;
	}

	public List<Integer> getFullLineNo() {
		return fullLineNo;
	}

	public void setFullLineNo(List<Integer> fullLineNo) {
		this.fullLineNo = fullLineNo;
	}
}
